#include "stdafx.h"
#include "mainrun.h"
#include "plugins.h"

CMainRun::CMainRun(void)
{
	m_strRunPath.clear();
	m_RunPlugin = COMPONENT_NULL;
	m_argc = 0;
	m_argv = NULL;
	m_hInstance = INSNULL;
}

CMainRun::~CMainRun(void)
{
	logi("CMainRun::~CMainRun");
}

std_method_impl CMainRun::RegisterCode(LPCSTR buf, ULONG ulen)
{
	HRESULT hr = S_OK;
	rc_assert(buf != NULL, OBJECT_RUN_RET_PARAMERR);
	hr = RegisterPlugins(buf);
	rc_assert(hr == S_OK, OBJECT_RUN_RET_MEMERR);

	m_strRegisterCode.clear();
	m_strRegisterCode.append(buf);

	return hr;
}

std_method_type_impl(LPCSTR) CMainRun::GetRegisterCode()
{
	return m_strRegisterCode.c_str();
}

std_method_impl CMainRun::SetPath(LPSTRING run, UINT len)
{
	rc_assert(len != 0, E_FAIL);
	rc_assert(run != 0, E_FAIL);
	m_strRunPath.clear();
	m_strRunPath.append(run);

	logi("s_strcpy_func %p\n", s_strcpy);
	m_strContainer.clear();
	TCHAR szPluginName[DYNAMIC_NAME_LEN + 1] = { 0x00 };
	GetDynamicName(_T("container"), szPluginName, DYNAMIC_NAME_LEN);
	m_strContainer = m_strRunPath;
	m_strContainer.append(path_slash);
	m_strContainer.append(szPluginName);
	
	return S_OK;
}
std_method_type_impl(LPSTRING) CMainRun::GetPath()
{
	return m_strRunPath.c_str();
}

std_method_impl CMainRun::Init(_pinstance hInstance, basic_tchar* argv[], int iargc)
{
	HRESULT hr =  S_OK;

	m_hInstance = hInstance;

	hr = RegisterRotAndlibManager();
	rc_assert(hr == S_OK, OBJECT_RUN_RET_ROTERR);

	hr = RegisterPluginComponents();
	rc_assert(hr == S_OK, OBJECT_RUN_RET_COMPERR);

	hr = RegisterPluginClsid();
	rc_assert(hr == S_OK, OBJECT_RUN_RET_CLSIDERR);

	hr = RegisterRunArgc(iargc, argv);
	rc_assert(hr == S_OK, OBJECT_RUN_RET_CLSIDERR);

	return hr;
}


std_method_impl CMainRun::Start(_pinstance instance, UINT type)
{
	return DoPluginsStartFunc(m_argc, m_argv, type);
}

std_method_impl CMainRun::Stop(_pinstance instance, UINT type,UINT exit)
{
	return DoPluginsStopFunc(type, exit);
}

std_method_type_impl(UINT) CMainRun::Run(_pinstance instance, UINT type)
{
	return DoPluginsRun(m_argc, m_argv, type);
}

std_method_impl CMainRun::NotifyExit(_pinstance instance, UINT exit)
{
	ExitPtr pExit;
	m_pRot->GetObject(m_RunPlugin, IID_IExit, (IBase**)&pExit);
	rc_assert(pExit.m_p != INULL, OBJECT_RUN_RET_SUCCESS);
	return pExit->OnExit(exit);
}

std_method_impl CMainRun::Uninit(_pinstance hInstance)
{
	rc_assert(m_pRot.m_p != INULL, E_FAIL);

	rc_assert(m_plibManager.m_p != INULL, E_NOINTERFACE)


	UninitAllPlugins();

	DestroyAllRotPlugin();

	m_plibManager->Free();

	Reset();

	return S_OK;
}

std_method_impl CMainRun::Clear()
{
	return Reset();
}

std_method_impl CMainRun::GetRot(IBase** Base)
{
	rc_assert(m_pRot.m_p != INULL, E_NOINTERFACE);
	return m_pRot->QueryInterface(IID_IComRunningObjectTable, (void**)Base);
}

std_method_impl CMainRun::GetObjectLoader(IBase** Base)
{
	rc_assert(m_pRot.m_p != INULL, E_NOINTERFACE);
	return m_pRot->GetObject(CLSID_CObjectLoader, IID_ICompoentLoader, (IBase**)Base);
}

std_method_impl CMainRun::AddObject(REFCLSID clsid, LPCSTR progId, IBase* pBase, UINT Id, LPCSTR Component, UINT type)
{
	HRESULT hr = S_OK;

	BasePtr pObject;
	hr = pBase->QueryInterface(IID_IBase, (void**)&pObject);
	rc_assert(pObject.m_p != NULL, E_FAIL)
	rc_assert(hr == S_OK,E_FAIL);

	PluginPtr pPlugin;
	hr = pBase->QueryInterface(IID_IPlugin, (void**)&pPlugin);
	rc_assert(hr == S_OK, E_FAIL)
	rc_assert(pPlugin.m_p != NULL, E_FAIL)


	if(type & STD_INIT)
		hr = pPlugin->Init(m_argc, m_argv, m_pRot, NULL);

	if (type & STD_START)
		hr = RunPlugin_Start(m_hInstance, pObject, 0);

	if (type & STD_ROT)
		hr = m_pRot->Register(clsid, progId, pBase, Id);

	if (type & STD_VEC)
		m_PluginsDynamicClsid.push_back(Com_Plugin(clsid, Id, Component));

	if (type & STD_SEQ_VEC)
		m_PluginsClsid.push_back(Com_Plugin(clsid, Id, Component));
	
	return S_OK;

}

std_method_impl CMainRun::DelObject(REFCLSID clsid, LPCSTR progId, IBase* pBase, UINT Id, LPCSTR Component, UINT type)
{
	return E_NOTIMPL;
}

std_method_type_impl(CLSID) CMainRun::GetRunPluginCLSID()
{
	return m_RunPlugin;
}

std_method_type_impl(ULONG) CMainRun::GetRunPluginsCount()
{
	return m_PluginsClsid.size();
}

std_method_type_impl(int) CMainRun::GetArgc()
{
	return m_argc;
}
std_method_type_impl(basic_tchar*) CMainRun::GetIndexArgv(int index)
{
	rc_assert(((index >= 0) && (index < m_argc)), NULL)
	return m_argv[index];
}
std_method_type_impl(ULONG) CMainRun::GetRunIndex(ULONG index)
{
	rc_assert(((index >= 0) && (index < m_PluginsClsid.size())), 0)
	return m_PluginsClsid[index].uIndex;
}
std_method_type_impl(UINT) CMainRun::GetExitCode()
{
	return GetIExitCode(m_RunPlugin);
}

std_method_impl CMainRun::RegisterRunArgc(int iArgc, basic_tchar* Argv[])
{
	m_argc = iArgc;
	m_argv = Argv;
	return S_OK;
}

std_method_impl CMainRun::RegisterPlugins(LPCSTR Buf)
{
	return m_Plugins.LoadMemory(Buf);
}

std_method_impl	CMainRun::RegisterPluginClsid()
{
	DWORD dwCount = 0;
	m_PluginsClsid.clear();
	dwCount = m_Plugins.LoadClsidAll(m_PluginsClsid);
	rc_assert(dwCount > 0, E_FAIL);

	UINT uloop = 0;

	for (uloop = 0; uloop < dwCount; uloop++)
	{
		CreatePlugin(m_PluginsClsid[uloop].ClsId, uloop);
	}
	return S_OK;
}

std_method_impl	CMainRun::RegisterPluginComponents()
{
	DWORD dwCount = 0;
	m_PluginsComponents.clear();
	dwCount = m_Plugins.LoadCompents(m_PluginsComponents);
	rc_assert(dwCount > 0, E_FAIL);

	ComponentPluginIterator it = m_PluginsComponents.begin();
	
	while(it != m_PluginsComponents.end()) 
	{
		HRESULT hr = RegisterContainer(it->first.c_str());

		if (S_FAILED(hr))
		{
			logi("RegisterClsid ==>guid:%s", it->first.c_str());
		}
		it++;
	}
	return S_OK;
}
std_method_impl	CMainRun::RegisterRotAndlibManager()
{

	HRESULT hr = S_OK;

	ComFactoryPtr pClassFactory;
	BasePtr	pIBase;
	pClassFactory.dispose();

	hr = DllGetClassObject(ClSID_CComRunningObjectTable, IID_IComObjectFrameworkClassFactory, (void**)&pClassFactory);
	rc_assert(hr == S_OK, E_FAIL)
	rc_assert(pClassFactory.m_p != INULL, E_FAIL);

	hr = pClassFactory->CreateInstance(NULL, NULL, IID_IComRunningObjectTable, (void**)&m_pRot);
	rc_assert(hr == S_OK, E_FAIL)
	rc_assert(m_pRot.m_p != INULL, E_FAIL);

	pClassFactory.dispose();
	pIBase.dispose();

	hr = DllGetClassObject(CLSID_CObjectLoader, IID_IComObjectFrameworkClassFactory, (void**)&pClassFactory);
	rc_assert(hr == S_OK, E_FAIL)
	rc_assert(pClassFactory.m_p != INULL, E_FAIL);

	hr = pClassFactory->CreateInstance(NULL, NULL, IID_IBase, (void**)&pIBase);
	rc_assert(hr == S_OK, E_FAIL)
	rc_assert(pIBase != INULL, E_FAIL);
	
	hr = pIBase->QueryInterface(IID_ILibManager, (void**)&m_plibManager);
	rc_assert(hr == S_OK, E_FAIL)

	hr = m_pRot->Register(CLSID_CObjectLoader, "ObjectLoader.impl.V1", pIBase, 0);
	rc_assert(hr == S_OK, E_FAIL)
	
	pClassFactory.dispose();
	pIBase.dispose();

	hr = this->QueryInterface(IID_IBase, (void**)&pIBase);
	rc_assert(hr == S_OK, E_FAIL)
	rc_assert(pIBase.m_p != INULL, E_FAIL);

	hr = m_pRot->Register(CLSID_CObjectRun, "ObjectRun.impl.V1", pIBase, 0);
	rc_assert(hr == S_OK, E_FAIL)

	pClassFactory.dispose();
	pIBase.dispose();

	return hr;
}

std_method_impl	CMainRun::RegisterContainer(LPCSTR name)
{
	rc_assert(name != NULL, E_FAIL);
	basic_tstring modpath = ComponentPath(name);
	return m_plibManager->Load(modpath.c_str(), name);
}

std_method_impl	CMainRun::CreatePlugin(REFCLSID iid, UINT index)
{

	char guid[GUIDStringLength] = { 0x00 };
	GUIDToString(&iid, guid);

	BasePtr pBase;
	HRESULT hr = CreateRotPlugin(iid, (IBase **)&pBase, index);

	if (S_FAILED(hr))
	{
		logi("create_plugin_error==>guid==>%s", guid);
		return hr;
	}
	PluginPtr pPlugin;
	hr = pBase->QueryInterface(IID_IPlugin, (void**)&pPlugin);
	rc_assert(hr == S_OK, E_FAIL)

	if (pPlugin)
	{
		hr = pPlugin->Init(m_argc, m_argv, m_pRot, NULL);

		if (S_FAILED(hr))
		{
			logi("init_plugin_error==>guid==>%s", guid);
			pPlugin->Uninit();
			DestroyRotPlugin(iid);
		}
	}
	return hr;
}


std_method_impl CMainRun::UninitAllPlugins()
{
	rc_assert(m_PluginsClsid.size() > 0, S_OK);
	rc_assert(m_pRot.m_p != INULL, E_FAIL);

	ULONG uSize = 0;
	uSize = m_PluginsClsid.size();

	ULONG uloop = 0;
	HRESULT hr = S_OK;

	for (uloop = 0 ; uloop < uSize; uloop++)
	{
		ULONG index = uSize - uloop - 1;
		rc_assert_continue(((index >= 0) && (index <uSize)))

		BasePtr pUnknown;
		hr = m_pRot->GetObject(m_PluginsClsid[index].ClsId, IID_IBase, (IBase**)&pUnknown);
		rc_assert_continue(hr == S_OK);

		PluginPtr pPlugin;
		hr = pUnknown->QueryInterface(IID_IPlugin, (void**)&pPlugin);
		rc_assert_continue(hr == S_OK);


		if(pPlugin)
		{
			pPlugin->Uninit();
		}
		else
		{
			char guid[GUIDStringLength] = {0x00};
			GUIDToString(&m_PluginsClsid[index].ClsId, guid);
			logi("uinit_plugin_error==>guid:%s", guid);
		}
	}


	uSize = m_PluginsDynamicClsid.size();

	for (uloop = 0; uloop < uSize; uloop++)
	{
		ULONG index = uSize - uloop - 1;
		rc_assert_continue(((index >= 0) && (index < uSize)))

		BasePtr pUnknown;
		hr = m_pRot->GetObject(m_PluginsDynamicClsid[index].ClsId, IID_IBase, (IBase**)&pUnknown);
		rc_assert_continue(hr == S_OK);

		PluginPtr pPlugin;
		hr = pUnknown->QueryInterface(IID_IPlugin, (void**)&pPlugin);
		rc_assert_continue(hr == S_OK);

		if (pPlugin)
		{
			pPlugin->Uninit();
		}
	}


	return S_OK;
}


std_method_impl CMainRun::CreateRotPlugin(REFCLSID iid, IBase **ppunk, UINT index)
{
	rc_assert(iid != COMPONENT_NULL, E_FAIL);
	rc_assert(m_pRot.m_p != INULL, E_FAIL);

	HRESULT hr = S_OK;
	hr = m_pRot->CreateInstance(m_pRot, iid, NULL, IID_IBase, (void**)ppunk);
	rc_assert(hr == S_OK, E_FAIL);
	rc_assert(*ppunk !=NULL, E_FAIL);

	LPCSTR	progid = m_pRot->ProgIDFromCLSID(iid);

	return  m_pRot->Register(iid, progid, *ppunk, index);
}

std_method_impl CMainRun::DestroyAllRotPlugin()
{
	rc_assert(m_PluginsClsid.size() > 0, S_OK);
	rc_assert(m_pRot.m_p != INULL, E_FAIL);


	ULONG Size = 0;
	Size = m_PluginsClsid.size();
	//free index ==>std plugin free 
	//static plugin
	ULONG uloop = 0;
	for (uloop = 0; uloop < Size; uloop++)
	{
		ULONG index = Size - uloop - 1;
		rc_assert_continue(((index >= 0) && (index < Size)))
		DestroyRotPlugin(m_PluginsClsid[index].ClsId);
	}

	Size = m_PluginsDynamicClsid.size();
	//dynamic plugin
	for (uloop = 0; uloop < Size; uloop++)
	{
		ULONG index = Size - uloop - 1;
		rc_assert_continue(((index >= 0) && (index < Size)))
		DestroyRotPlugin(m_PluginsDynamicClsid[index].ClsId);
	}

	//
	DestroyRotPlugin(CLSID_CObjectRun);

	DestroyRotPlugin(CLSID_CObjectLoader);

	return m_pRot->RevokeAll();
}

std_method_impl CMainRun::DestroyRotPlugin(REFCLSID iid)
{
	rc_assert(iid != COMPONENT_NULL, E_FAIL);
	rc_assert(m_pRot.m_p != NULL, E_FAIL);
	return m_pRot->Revoke(iid);
}

std_method_type_impl(UINT) CMainRun::DoPluginsRun(int iArgc, basic_tchar* Argv[], UINT uType)
{
	HRESULT hr = S_OK;
	UINT uExit = OBJECT_RUN_RET_SUCCESS;

	//Do not care about the start stop function running results
	hr = DoPluginsStartFunc(m_argc, m_argv, uType);

	uExit = GetIExitCode(m_RunPlugin);

	logi("exit_code==>%u", uExit);

	hr = DoPluginsStopFunc(uType, uExit);

	return uExit;
}

std_method_impl CMainRun::DoPluginsStartFunc(int iArgc, basic_tchar* Argv[], UINT uType)
{
	HRESULT hr = S_OK;

	ULONG uSize = m_PluginsClsid.size();
	rc_assert(uSize > 0, S_OK);
	rc_assert(m_pRot.m_p != INULL, E_FAIL);
	ULONG uloop = 0;

	for (uloop = 0; uloop < uSize; uloop++)
	{
		rc_assert(( uloop >= 0  && uloop < m_PluginsClsid.size()), E_FAIL)

		BasePtr pUnknown;
		hr = m_pRot->GetObject(m_PluginsClsid[uloop].ClsId, IID_IBase, (IBase**)&pUnknown);
		rc_assert_continue(hr == S_OK);

		char guid[GUIDStringLength] = { 0x00 };
		GUIDToString(&m_PluginsClsid[uloop].ClsId, guid);

		m_RunPlugin = m_PluginsClsid[uloop].ClsId;
		
		logi("run plugin==>%s==>%s\n",m_PluginsClsid[uloop].szComponent.c_str(), guid);
		RunPlugin_Start(m_hInstance, pUnknown, uType);
	}
	return hr;
}

std_method_impl CMainRun::DoPluginsStopFunc(UINT uType, UINT uExit)
{
	HRESULT hr = S_OK;
	ULONG uSize = m_PluginsClsid.size();
	rc_assert(uSize > 0, S_OK);
	rc_assert(m_pRot.m_p != INULL, E_FAIL);
	ULONG uloop = 0;
	
	for (uloop = 0; uloop < m_PluginsDynamicClsid.size(); uloop++ ) {
	
		rc_assert((uloop >= 0 && uloop < m_PluginsDynamicClsid.size()), E_FAIL)

		unsigned long index = m_PluginsDynamicClsid.size() - uloop - 1;
		rc_assert_continue(((index >= 0) && (index < m_PluginsDynamicClsid.size())))

		BasePtr pUnknown;
		hr = m_pRot->GetObject(m_PluginsDynamicClsid[index].ClsId, IID_IBase, (IBase**)&pUnknown);
		rc_assert_continue(hr == S_OK);

		char guid[GUIDStringLength] = { 0x00 };
		GUIDToString(&m_PluginsDynamicClsid[uloop].ClsId, guid);

		RunPlugin_Stop(m_hInstance, pUnknown, uExit);
	}
	
	for (uloop = 0; uloop < uSize; uloop++)
	{
		rc_assert((uloop >= 0 && uloop < m_PluginsClsid.size()), E_FAIL)

		unsigned long index = uSize - uloop - 1;
		rc_assert_continue(((index >= 0) && (index < m_PluginsClsid.size())))

		BasePtr pUnknown;
		hr = m_pRot->GetObject(m_PluginsClsid[index].ClsId, IID_IBase, (IBase**)&pUnknown);
		rc_assert_continue(hr == S_OK);

		char guid[GUIDStringLength] = { 0x00 };
		GUIDToString(&m_PluginsClsid[uloop].ClsId, guid);

		RunPlugin_Stop(m_hInstance, pUnknown, uExit);

	}
	return hr;
}

std_method_type_impl(UINT) CMainRun::GetIExitCode(CLSID iid)
{
	ExitPtr pExit;
	m_pRot->GetObject(iid, IID_IExit, (IBase**)&pExit);
	rc_assert(pExit.m_p != INULL, OBJECT_RUN_RET_SUCCESS);
	return pExit->GetExitCode();
}

std_method_impl CMainRun::RunPlugin_Start(_pinstance hInstance, BaseConstPtr pBase, UINT uType)
{
	RunMsgPlugin_Start(pBase);

	return RunStdPlugin_Start(m_hInstance, pBase, uType);
}
std_method_impl CMainRun::RunPlugin_Stop(_pinstance hInstance, BaseConstPtr pBase, UINT uExit)
{
	RunMsgPlugin_Stop(pBase);
	return RunStdPlugin_Stop(m_hInstance, pBase, uExit);
}

std_method_impl CMainRun::RunStdPlugin_Start(_pinstance hInstance, BaseConstPtr pBase, UINT uType)
{
	HRESULT hr = S_OK;
	PluginRunPtr pPluginRun;
	hr = pBase->QueryInterface(IID_IPluginRun, (void**)&pPluginRun);
	rc_assert(hr == S_OK, E_FAIL);
	rc_assert(pPluginRun.m_p, E_FAIL);
	return pPluginRun->Start(hInstance, uType);
}

std_method_impl CMainRun::RunStdPlugin_Stop(_pinstance hInstance, BaseConstPtr pBase, UINT uExit)
{
	HRESULT hr = S_OK;
	PluginRunPtr pPluginRun;
	hr = pBase->QueryInterface(IID_IPluginRun, (void**)&pPluginRun);
	rc_assert(hr == S_OK, E_FAIL);
	rc_assert(pPluginRun.m_p, E_FAIL);

	return pPluginRun->Stop(uExit);
}

std_method_impl CMainRun::RunMsgPlugin_Start(BaseConstPtr pBase)
{
	return S_OK;
}

std_method_impl CMainRun::RunMsgPlugin_Stop(BaseConstPtr pBase)
{
	return S_OK;
}

std_method_impl	CMainRun::Reset()
{
	m_strRunPath.clear();
	m_PluginsClsid.clear();
	m_PluginsComponents.clear();
	m_argc = 0;
	m_argv = NULL;
	m_RunPlugin = COMPONENT_NULL;

	return S_OK;
}

std_method_type_impl(basic_tstring) CMainRun::ComponentPath(LPCSTR ComponentName)
{
	basic_tstring stringpath;
	stringpath.clear();
	stringpath.append(m_strRunPath);
	stringpath.append(path_slash);

#if (TARGET_OS == OS_WINDOWS)
	SafePtr<basic_tchar*, ChartoUcs2Struct> pBuf;
	pBuf = char_to_ucs2(ComponentName, s_strlen(ComponentName));
	basic_tchar szPluginName[DYNAMIC_NAME_LEN + 1] = { 0x00 };
	GetDynamicName(pBuf, szPluginName, DYNAMIC_NAME_LEN);
#elif (TARGET_OS == OS_POSIX)
	basic_tchar szPluginName[DYNAMIC_NAME_LEN + 1] = { 0x00 };
	GetDynamicName(ComponentName, szPluginName, DYNAMIC_NAME_LEN);
#elif (TARGET_OS == OS_DARWIN)
	basic_tchar szPluginName[DYNAMIC_NAME_LEN + 1] = { 0x00 };
	GetDynamicName(ComponentName, szPluginName, DYNAMIC_NAME_LEN);
#endif // MSC_VER

	stringpath += szPluginName;
	return stringpath;
}


